﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Big2.Big2WcfService;
using Big2.CardsLib;
using Big2.Big2Game;
using System.Windows.Threading;
using System.Threading;
using System.Collections.ObjectModel;

namespace Big2.Big2WfpGui
{
    /// <summary>
    /// Interaction logic for Big2Room.xaml
    /// </summary>
    
    public partial class Big2Room : Window
    {

        #region variables
        Client client;
        public Game TheGame;
        Connect connection;
        public StringDependencyObject systemMessageDepObj;
        public StringDependencyObject talkHistoryDepObj;
        public ObservableCollection<StringDependencyObject> _playersAndChattersCollection;
        public List<CardImage> selectedCardImageList;
        public Hand playerHand = null;
        public List<String> PlayersInGame;
        #endregion

        public ObservableCollection<StringDependencyObject> playersAndChattersCollection
        {
            get
            {
                if (_playersAndChattersCollection == null)
                    _playersAndChattersCollection = new ObservableCollection<StringDependencyObject>();
                return _playersAndChattersCollection;
            }
        }

        #region constructors
        public Big2Room()
        {
            InitializeComponent();
        }
        #endregion


        #region event handlers
        private void btTalk_Click(object sender, RoutedEventArgs e)
        {
            client.proxy.Talk(connection.GetName,tbTalk.Text);
            tbTalk.Text = "";  
        }
        private void btJoinGame_Click(object sender, RoutedEventArgs e)
        {
            btJoinGame.Visibility = Visibility.Hidden;
            int status = client.proxy.JoinGame(connection.GetName);
            if (status == -1)
            {
                WriteSystemMSG("System>>> Unabled to join game, it's currently full");
                btJoinGame.Visibility = Visibility.Visible;
            }
            else if (status == 0)
                WriteSystemMSG("System>>> You have joined the game.");
        }

        void image_CardClicked(object sender, MouseButtonEventArgs e)
        {
            CardImage i = sender as CardImage;
            if (i.Selected)
            {
                i.Selected = false;
                i.RenderTransform = new TranslateTransform(0, 0);

                selectedCardImageList.Remove(i);
            }
            else
            {
                i.Selected = true;
                i.RenderTransform = new TranslateTransform(0, -10);

                selectedCardImageList.Add(i);
            }
        }

        private void btPlay_Click(object sender, RoutedEventArgs e)
        {
            
            WriteSystemMSG("player plays cards..");
            List<Card> selectedCards=new List<Card>();
            
            
            selectedCardImageList.ForEach(delegate(CardImage c) { selectedCards.Add(c.TheCard); });

            if (!Play.IsValidPlay(CardHelper.SortCards(selectedCards, true)))
            {
                WriteSystemMSG("Selected cards is an invalid play.");
                return;
            }

            int result=client.proxy.PlayCard(connection.GetName,selectedCards);
            WriteSystemMSG("return value from play card is: " + result);

            if (result == 0)
            {
                CardHelper.RemoveCards(playerHand.CardsList, selectedCards);
                this.DispatchInvoke((Action)delegate
                    {
                        canvasSeat1.Children.Clear();
                    }
                );


                DrawCards(canvasSeat1, playerHand.CardsList, 1, true, true);
                EnabledPlayMenu(false);

                selectedCards.Clear();
                selectedCardImageList.Clear();
            }

            
        }

        private void btPass_Click(object sender, RoutedEventArgs e)
        {
            client.proxy.Pass(connection.GetName);

            btPass.Visibility = Visibility.Hidden;
            btPlay.Visibility = Visibility.Hidden;
        }
        
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            SetupUI();
            TheGame = new Game();
            selectedCardImageList = new List<CardImage>();

            LoginControl.Visibility = Visibility.Visible;
            LoginControl.Opacity = 1;
            LoginControl.ReadyToLogin += new Login.ReadyToLoginEventHandler(ReadyToLogin);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            try
            {
                client.DisconnectClient();
                if (connection.IsServer)
                {
                    TheGame.Server.CloseServer();
                }
            }
            catch { }
        }

        #endregion

        



        #region region call back interface methods
        public void ClientDisconnected()
        {
            
        }
        public void ClientConnected(List<string> n)
        {
            //foreach (string user in n)
            //    this.DispatchInvoke((Action)delegate { lbUsers.Items.Add(user); });
            //lbUsers.Items.Dispatcher.Invoke(DispatcherPriority.DataBind,((Action)delegate {lbUsers.Items.Clear(); lbUsers.ItemsSource = n; }) );

            //MessageBox.Show("client logged in..");
            WriteSystemMSG("Connected successfully..");
            this.DispatchInvoke((Action)delegate { LoginControl.Visibility = Visibility.Hidden; rectangle1.Visibility = Visibility.Hidden; });


            //DrawCard(canvasSeat2, null);
        }
        public void PlayerLeft(string player)
        {
            //TODO: remove player to listbox
            WriteSystemMSG(player + " left the room.");
        }
        public void PlayerJoin(string player)
        {
            //TODO: add player to listbox
            AddPlayerToListbox(player);
            WriteSystemMSG(player + " joined the room.");
        }
        public void GameStarted(List<string> playersInGame)
        {
            DispatchInvoke((Action)delegate {
            btJoinGame.Visibility = Visibility.Hidden;
            WriteSystemMSG("System>>> Game started\n");
            });

            PlayersInGame = playersInGame;
        }        
        public void DealHandToPlayer(Hand hand)
        {
            playerHand = hand;
            WriteSystemMSG(String.Format("System>>> New hand received({0} Cards).\n",hand.CardsList.Count)); 
            foreach(Card c in hand.CardsList)
                WriteSystemMSG("System>>" + c.ToString() + " , ");
            WriteSystemMSG("System>>>\n");

            hand.CardsList=CardHelper.SortCards(hand.CardsList,true);
            DrawCards(canvasSeat1, hand.CardsList, 1, true, true);            
            DrawCards(canvasSeat2, hand.CardsList,2,false,false);
            if (PlayersInGame.Count > 2)
                DrawCards(canvasSeat3, hand.CardsList, 1, false, false);
            if(PlayersInGame.Count>3)
                DrawCards(canvasSeat4, hand.CardsList, 2, false, false);
            //userarea1.Bind(hand.CardsList);
            //userarea2.Bind(hand.CardsList);
        }
        public void CurrentPlay(Play currentPlay)
        {
            WriteSystemMSG("CurrentPlay called");
            List<CardImage> temp = new List<CardImage>();  
            this.DispatchInvoke( (Action)delegate {
            lbCurrentPlay.DataContext = null;
            lbCurrentPlay.DataContext = CreateCardImageList(currentPlay.CardsList);
            });
        }
        public void PlayerTurn(Play currentPlay)
        {
            WriteSystemMSG("Player Turn called");
            //TODO: Add code to highlight the current player's seat, so players know who's turn it is
            EnabledPlayMenu(true);
        }
        public void GameEnd(string winnderName, List<Player> players)
        {
            WriteSystemMSG("Game end in big2room called.  Winner is : " + winnderName);

            //show scores
            this.DispatchInvoke((Action)delegate
            {
                UserScores.PlayerScoresClosed += new PlayerScores.PlayerScoresClosedEvent(PlayerScoresClosed);
                UserScores.DisplayScores(players,5);
                UserScores.Visibility = Visibility.Visible;
            });


            
        }

        void PlayerScoresClosed()
        {
            this.DispatchInvoke((Action)delegate
                {
                    UserScores.Visibility = Visibility.Hidden;
                }
            );
            //initialized new games
            ResetGame();
            client.proxy.StartGame(connection.GetName);
        }

        private void ResetGame()
        {
            playerHand = null ;

            this.DispatchInvoke((Action)delegate
            {
                canvasSeat1.Children.Clear();
                canvasSeat2.Children.Clear();
                canvasSeat3.Children.Clear();
                canvasSeat4.Children.Clear();
                canvasSeatCenter.Children.Clear();
            }
                );

            EnabledPlayMenu(false);

            //selectedCards.Clear();
            selectedCardImageList.Clear();
        }
        public void NewTalkMSG(string msg)
        {           
            //DispatchInvoke((Action) delegate{ tbTalkHistory.Text=msg + "\n" + tbTalkHistory.Text;});
            talkHistoryDepObj.Message = msg + "\n" + talkHistoryDepObj.Message;
        }

        #endregion

        private void ReadyToLogin(Connect c,Rules r)
        {
            connection = c;
            //MessageBox.Show("Connect clicked");
            if (c.IsServer==false)
            {
                
                ClientLogin(c);
            }
            else
            {
                StartServer(c,r);
                //this.DispatchInvoke((Action)delegate { StartServer(); });
            }
        }

        private void ClientLogin(Connect c)
        {
            client = new Client();
            client.Connection = c;
            client.ClientConnected += new Client.ClientConnectedEventHandler(ClientConnected);
            client.ClientDisconnected += new Client.ClientDisconnectedEventHandler(ClientDisconnected);
            client.DealHandToPlayerEventCalled+=new Client.DealHandToPlayerEventHandler(DealHandToPlayer);
            client.PlayerLeftEventCalled+=new Client.PlayerLeftEventHandler(PlayerLeft);
            client.NewTalkMSGEventCalled += new Client.NewTalkMSGEventHandler(NewTalkMSG);
            client.PlayerJoinEventCalled += new Client.PlayerJoinEventHandler(PlayerJoin);
            client.GameStartedEventCalled += new Client.GameStartedEventHandler(GameStarted);
            client.CurrentPlayEventCalled += new Client.CurrentPlayEventHandler(CurrentPlay);
            client.PlayerTurnEventCalled += new Client.PlayerTurnEventHandler(PlayerTurn);
            client.GameEndEventCalled += new Client.GameEndEventHandler(GameEnd);

            client.ConnectToServer();
            
        }
             
        private void StartServer(Connect c,Rules r)
        {
            //server = new Server();
            TheGame.InitGameServer();
            TheGame.Server.Connection = c;
            TheGame.GameRules = r;
            Big2ServerService.ServerStarted += new Big2ServerService.ServerStartedEventHandler(server_ServerStarted);
            TheGame.Server.startServer();
        }
        void server_ServerStarted()
        {
            WriteSystemMSG("Server started");
            ClientLogin(connection);
        }


        #region gui helper methods
        private void SetupUI()
        {
            //set up system message
            systemMessageDepObj = new StringDependencyObject();
            System.Windows.Data.Binding b = new System.Windows.Data.Binding("Message");
            b.Source = systemMessageDepObj;
            tbSystemMSG.SetBinding(TextBox.TextProperty, b);

            //hide play menu
            EnabledPlayMenu(false);

            //set up talk history textbox
            talkHistoryDepObj = new StringDependencyObject();
            b = new System.Windows.Data.Binding("Message");
            b.Source = talkHistoryDepObj;
            tbTalkHistory.SetBinding(TextBox.TextProperty, b);

            //player list box
            //_playersAndChattersCollection = new ObservableCollection<StringDependencyObject>();
            //b = new System.Windows.Data.Binding("playersAndChatters");
            //b.Source = playersAndChattersCollection;
            //lbUsers.SetBinding(ListBox.ItemsSourceProperty, b);

            StringDependencyObject d = new StringDependencyObject();
            d.Message = "test";
            playersAndChattersCollection.Add(d);

            d = new StringDependencyObject();
            d.Message = "test22";
            playersAndChattersCollection.Add(d);


            //DrawingGroup drawingGroup = new DrawingGroup();
            //ImageDrawing imageDrawing = new ImageDrawing();
            //BitmapImage bitmapImage=new BitmapImage(new Uri(@"./images/King of Clubs.png"));
            //imageDrawing.ImageSourceProperty = bitmapImage;
            //imageDrawing.Rect(10, 0, bitmapImage.Width, bitmapImage.Height);
            //drawingGroup.Children.Add(imageDrawing);

            //DrawingBrush db = new DrawingBrush(drawingGroup);
            //canvasSeat3.Children.Add(drawingGroup);


        }
        private void DispatchInvoke(Delegate x)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.DataBind, x);
        }
        void WriteSystemMSG(string msg)
        {
            //this.DispatchInvoke((Action)delegate { tbSystemMSG.Text = "System>> " + msg + "\n" + tbSystemMSG.Text; });
            systemMessageDepObj.Message = "System>> " + msg + "\n" + systemMessageDepObj.Message;
        }
        private void AddPlayerToListbox(string player)
        {
            //this.DispatchInvoke((Action)delegate { if (!lbUsers.Items.Contains(player)) lbUsers.Items.Add(lbUsers); });
        }
        public void DrawCards(Canvas c, List<Card> cards,int orientation,bool isFaceUp,bool addHandler)
        {
            c.Dispatcher.Invoke(DispatcherPriority.DataBind, (Action)delegate
            {
                int x = 10, y = 10, cardMargin = 20 ;
                CardImage image;      
 
                if (orientation == 2)
                    y += CardImage.CardWidth;

                for (int i = 0; i < cards.Count; i++)
                {    
                    image = new CardImage();
                    image.FaceUp=isFaceUp;
                    image.TheCard = cards[i];
                    image.Selected = false;
                    image.SetSource();
                    
                    if (orientation == 2)
                    {
                        image.RenderTransform = new RotateTransform(270);
                        y += cardMargin;
                    }
                    else
                    {
                        x += cardMargin;
                    }                    
                    Canvas.SetLeft(image, x);
                    Canvas.SetTop(image, y);                    
                    c.Children.Add(image);
                    Control t = new Control();
                    
                    if (addHandler)
                    {
                        image.MouseLeftButtonUp += new MouseButtonEventHandler(image_CardClicked);
                    }
                    
                }             
            });

        }
        private List<CardImage> CreateCardImageList(List<Card> cl)
        {
            CardImage ci;
            List<CardImage> result = new List<CardImage>();
            foreach (Card c in cl)
            {
                ci = new CardImage();
                ci.FaceUp = true;
                ci.TheCard = c;
                ci.Selected = false;
                ci.SetSource();

                result.Add(ci);
            }
            return result;

        }
        private void EnabledPlayMenu(bool p)
        {
            if (p)
            {
                this.DispatchInvoke((Action)delegate
                {
                    btPass.Visibility = Visibility.Visible;
                    btPlay.Visibility = Visibility.Visible;
                }
                );
            }
            else
            {
                this.DispatchInvoke((Action)delegate
                {
                    btPass.Visibility = Visibility.Hidden;
                    btPlay.Visibility = Visibility.Hidden;
                }
                );
            }
        }
        #endregion




    }
}
